package com.mossle.bpm.jiaqian;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.activiti.engine.ActivitiException;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.pvm.delegate.ActivityExecution;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CountersignCommand implements Command<Object>{
	private static Logger log = LoggerFactory.getLogger(CountersignCommand.class);
	
	private String operateType;
	private String activityId;
	private String assignee;
	private String processInstanceId;
	private String collectionVariableName;
	private String collectionElementVariableName;
	private CommandContext commandContext;
	
	
	/**
	 * @param operateType 操作类型 add or remove 
	 * @param activityId 节点ID
	 * @param assignee 人员代码
	 * @param processInstanceId 流程实例ID
	 * @param collectionVariableName collection 设置的变量名
	 * @param collectionElementVariableName collection 的每个元素变量名
	 */
	public CountersignCommand(final String operateType,final String activityId,final String assignee, final String processInstanceId,final String collectionVariableName , final String collectionElementVariableName) {
		this.operateType = operateType;
		this.activityId = activityId;
		this.assignee = assignee;
		this.processInstanceId = processInstanceId;
		this.collectionVariableName = collectionVariableName;
		this.collectionElementVariableName = collectionElementVariableName;
	}
	
	
	public Object execute(CommandContext commandContext) {
		this.commandContext = commandContext;
		if(operateType.equalsIgnoreCase("add")){
			addInstance();
		}else if(operateType.equalsIgnoreCase("remove")){
			removeInstance();
		}
		return null;
	}
	
	
	/**
	 * <li> 加签
	 */
	public void addInstance(){
		if(isParallel()){
			addParallelInstance();
		}else{
			addSequentialInstance();
		}
		
	}
	
	/**
	 * <li> 减签
	 */
	public void removeInstance(){
		if(isParallel()){
			removeParallelInstance();
		}else{
			removeSequentialInstance();
		}
	}
	
	
	
	
	/**
	 * <li> 添加一条并行实例
	 */
	private void addParallelInstance(){
		ExecutionEntity parentExecutionEntity = commandContext.getExecutionEntityManager().findExecutionById(processInstanceId).findExecution(activityId);
		ActivityImpl activity = getActivity();
		ExecutionEntity execution = parentExecutionEntity.createExecution();
		execution.setActive(true);
		execution.setConcurrent(true);
		execution.setScope(false);
		if (getActivity().getProperty("type").equals("subProcess")) {
			ExecutionEntity extraScopedExecution = execution.createExecution();
			extraScopedExecution.setActive(true);
			extraScopedExecution.setConcurrent(false);
			extraScopedExecution.setScope(true);
			execution = extraScopedExecution;
		}
		setLoopVariable(parentExecutionEntity, "nrOfInstances", (Integer) parentExecutionEntity.getVariableLocal("nrOfInstances") + 1);
		setLoopVariable(parentExecutionEntity, "nrOfActiveInstances", (Integer) parentExecutionEntity.getVariableLocal("nrOfActiveInstances") + 1);
		setLoopVariable(execution, "loopCounter", parentExecutionEntity.getExecutions().size() + 1);
		setLoopVariable(execution, collectionElementVariableName, assignee);
		execution.executeActivity(activity);
	}
	
	
	/**
	 * <li> 给串行实例集合中添加一个审批人
	 */
	private void addSequentialInstance(){
		ExecutionEntity execution = getActivieExecutions().get(0);
		if (getActivity().getProperty("type").equals("subProcess")) {
			if (!execution.isActive() && execution.isEnded() && (execution.getExecutions() == null || execution.getExecutions().size() == 0)) {
				execution.setActive(true);
			}
		}
		Collection<String> col = (Collection<String>) execution.getVariable(collectionVariableName);
		col.add(assignee);
		execution.setVariable(collectionVariableName, col);
		setLoopVariable(execution, "nrOfInstances", (Integer) execution.getVariableLocal("nrOfInstances") + 1);
	}
	
	
	/**
	 * <li> 移除一条并行实例
	 */
	private void removeParallelInstance(){
		List<ExecutionEntity> executions = getActivieExecutions();
		for (ExecutionEntity executionEntity : executions) {
			String executionVariableAssignee = (String) executionEntity.getVariableLocal(collectionElementVariableName);
			if (executionVariableAssignee != null && executionVariableAssignee.equals(assignee)) {
				executionEntity.remove();
				ExecutionEntity parentConcurrentExecution = executionEntity.getParent();
				if (getActivity().getProperty("type").equals("subProcess")) {
					parentConcurrentExecution = parentConcurrentExecution.getParent();
				}
				setLoopVariable(parentConcurrentExecution, "nrOfInstances", (Integer) parentConcurrentExecution.getVariableLocal("nrOfInstances") - 1);
				setLoopVariable(parentConcurrentExecution, "nrOfActiveInstances", (Integer) parentConcurrentExecution.getVariableLocal("nrOfActiveInstances") - 1);
				break;
			}
		}
	}
	
	
	/**
	 * <li> 冲串行列表中移除未完成的用户(当前执行的用户无法移除)
	 */
	private void removeSequentialInstance(){
		ExecutionEntity executionEntity = getActivieExecutions().get(0);
		Collection<String> col = (Collection<String>) executionEntity.getVariable(collectionVariableName);
		log.info("移除前审批列表 : {}",col.toString());
		col.remove(assignee);
		executionEntity.setVariable(collectionVariableName, col);
		setLoopVariable(executionEntity, "nrOfInstances", (Integer) executionEntity.getVariableLocal("nrOfInstances") - 1);
		//如果串行要删除的人是当前active执行,
		if(executionEntity.getVariableLocal(collectionElementVariableName).equals(assignee)){
			throw new ActivitiException("当前正在执行的实例,无法移除!");
		}
		log.info("移除后审批列表 : {}",col.toString());
	}
	
	
	
	
	/**
	 * <li> 获取活动的执行 , 子流程的活动执行是其孩子执行(并行多实例情况下)
	 * <li> 串行情况下获取的结果数量为1
	 */
	protected List<ExecutionEntity> getActivieExecutions(){
		List<ExecutionEntity> activeExecutions = new ArrayList<ExecutionEntity>();
		ActivityImpl activity = getActivity();
		List<ExecutionEntity> executions = getChildExecutionByProcessInstanceId();
		for (ExecutionEntity execution : executions) {
			if(execution.isActive()&&(execution.getActivityId().equals(activityId)||activity.contains(execution.getActivity()))){
				activeExecutions.add(execution);
			}
		}
		return activeExecutions;
	}
	
	/**
	 * <li> 获取流程实例根的所有子执行
	 */
	protected List<ExecutionEntity> getChildExecutionByProcessInstanceId(){
		return commandContext.getExecutionEntityManager().findChildExecutionsByProcessInstanceId(processInstanceId);
	}
	
	/**
	 * <li>返回当前节点对象
	 */
	protected ActivityImpl getActivity(){
		return this.getProcessDefinition().findActivity(activityId);
	}
	
	/**
	 * <li> 判断节点多实例类型是否是并发
	 */
	protected boolean isParallel(){
		if(getActivity().getProperty("multiInstance").equals("parallel")){
			return true;
		}
		return false;
	}
	
	/**
	 * <li> 返回流程定义对象
	 */
	protected ProcessDefinitionImpl getProcessDefinition(){
		return this.getProcessInstanceEntity().getProcessDefinition();
	}
	
	/**
	 * <li> 返回流程实例的根执行对象
	 */
	protected ExecutionEntity getProcessInstanceEntity(){
		return commandContext.getExecutionEntityManager().findExecutionById(processInstanceId);
	}
	
	/**
	 * <li> 添加本地变量
	 */
	protected void setLoopVariable(ActivityExecution execution, String variableName, Object value) {
		execution.setVariableLocal(variableName, value);
	}

}
